import os
import socket

#from osc_base import OSCBaseObject
from Bases import OSCBaseObject, ChildGroup

import jsonhandler
import widgets

from pages.groups import GroupMasters
from pages.cuestacks import CueStacks
from pages.groupcontrol import GroupControl

PAGES = (GroupMasters, CueStacks, GroupControl)

class iOSCController(OSCBaseObject):
    def __init__(self, **kwargs):
        self.MainController = kwargs.get('MainController')
        self.comm = self.MainController.comm
        kwargs.setdefault('osc_parent_node', self.MainController.osc_parent_node)
        kwargs.setdefault('osc_address', 'iOSCControl')
        super(iOSCController, self).__init__(**kwargs)
        self.widgets = {}
        self.clients = {}
        
        for client in self.comm.osc_io.clients.itervalues():
            self.on_osc_client_added(client=client)
        self.comm.osc_io.bind(new_master=self.on_osc_new_master, 
                              client_added=self.on_osc_client_added, 
                              client_removed=self.on_osc_client_removed)
        
        #self.SelectionGroup = self.MainController.add_group(name='OSCControl', id='OSCControl', index=999)
        
        self.build_test_stuff()
        
    def _send_widget_to_client(self, **kwargs):
        w = kwargs.get('widget')
        clients = kwargs.get('clients')
        if not clients:
            clients = self.clients.values()
        if self.osc_node.oscMaster:
            root = self.osc_node.get_root_node()
            for client in clients:
                l = w.build_interface_dict(root_address=client.osc_name)
                for d in l:
                    s = jsonhandler.build_json(d)
                    #s = s.join(["\'"]*2)
                    root.send_message(root_address='control', address=['', 'addWidget'], value=s, 
                                      client=client.name)
        
    def add_widget(self, obj, **kwargs):
        def do_add_widget(w):
            self.widgets.update({w.id:w})
            #w.connect('interface_update', self.on_widget_interface_update)
            w.bind(interface_update=self.on_widget_interface_update, 
                   add_widget=self.on_widget_add_child, 
                   remove_widget=self.on_widget_remove_child)
            self._send_widget_to_client(widget=w)
            return w
            
        if isinstance(obj, widgets.BaseWidget):
            d = dict(osc_root_address=self.osc_address, 
                     osc_client_address='DWT_iPad')
            for key, val in d.iteritems():
                if getattr(obj, key) is None:
                    setattr(obj, key, val)
            return do_add_widget(obj)
            
        cls = None
        if type(obj) == str:
            cls = widgets.widget_classes.get(obj)
        elif issubclass(obj, widgets.BaseWidget):
            cls = obj
        if cls:
            w_kwargs = kwargs.copy()
            d = dict(osc_parent_node=self.osc_node, 
                     osc_root_address=self.osc_address, 
                     osc_client_address='DWT_iPad')
            for key, val in d.iteritems():
                if key not in w_kwargs:
                    w_kwargs[key] = val
            w = cls(**w_kwargs)
            return do_add_widget(w)
            
    def build_test_stuff(self):
#        self.group_masters = {}
#        for x in range(1, 13):
#            self.group_masters[x] = GroupMaster(iOsc=self, index=x)
        #self.GroupMasters = GroupMasters(iOsc=self)
            
        #self.CueStacks = CueStacks(iOsc=self, y_offset=.5)
        self.Menu = PageMenu(iOsc=self)
            
        s = self.build_interface(client_name='DWT_iPad', interface_name='test1', orientation='landscape', destination=['192.168.1.51', '18888'], js_kwargs={'indent':3})
        file = open(os.path.join(os.path.dirname(__file__), 'test_template.js'), 'w')
        file.write(s)
        file.close()
        
    def build_interface(self, **kwargs):
        client_name = kwargs.get('client_name')
        template = kwargs.get('template')
        name = kwargs.get('interface_name')
        orientation = kwargs.get('orientation')
        
        if not template:
            template = jsonhandler.load_template()
        script = template['script']
        if name:
            script = jsonhandler.set_script_vars(script, loadedInterfaceName=name)
        if orientation:
            script = jsonhandler.set_script_vars(script, interfaceOrientation=orientation)
        #dest = [str(self.comm.osc_io.hostdata[key]) for key in ['hostaddr', 'recvport']]
        #script += 'destinationManager.selectIPAddressAndPort("%s", "%s");' % (dest[0], dest[1])
        
        template['script'] = script
        
        for w in self.widgets.itervalues():
            l = w.build_interface_dict(root_address=client_name)
            template['pages'][0].extend(l)
            
        if 'js_kwargs' in kwargs:
            template['js_kwargs'] = kwargs['js_kwargs']
        return jsonhandler.build_interface(**template)
        
    def send_client_interface(self, **kwargs):
        name = kwargs.get('name')
        client = self.clients.get(name)
        if client:
            #s = self.build_interface(client_name=client.osc_name, orientation='landscape', interface_name='test1')
            #if len(s) > 4000:
            #    raise MsgLengthError
            #self.osc_node.get_root_node().send_message(root_address='control', address=['','pushInterface'],
            #                                           value=s, client=client.name)
            root = self.osc_node.get_root_node()
            local = self.comm.osc_io.local_client
            root.send_message(root_address='control', address=['', 'pushDestination'], 
                              value=':'.join([local.address, str(local.port)]), 
                              client=client.name)
            root.send_message(root_address='control', address=['', 'createBlankInterface'], 
                              value=['test2', 'landscape'], client=client.name)
            #root.send_message(root_address='control', address=['', 'setBounds'], 
            #                  value=['menuButton', .8, .85, .2, .15], client=client.name)
            for key in ['menuButton', 'menuButtonLabel']:
                root.send_message(root_address='control', address=['', 'removeWidget'], 
                                  value=[key], client=client.name)
            for w in self.widgets.itervalues():
                l = w.build_interface_dict(root_address=client.osc_name)
                for d in l:
                    s = jsonhandler.build_json(d)
                    #s = s.join(["\'"]*2)
                    root.send_message(root_address='control', address=['', 'addWidget'], value=s, 
                                      client=client.name)
                w.refresh_interface()
        
        
    def add_client(self, **kwargs):
        client = kwargs.get('client')
        if client.name not in self.clients:
            self.clients.update({client.name:client})
        #self.clients.update({name:tuple([kwargs.get(key) for key in ['address', 'port']])})
        if self.osc_node.oscMaster:
            self.send_client_interface(name=client.name)
            
    def remove_client(self, **kwargs):
        client = kwargs.get('client')
        if client.name in self.clients:
            del self.clients[client.name]
        self.Menu.set_current_page(None)
            
    def set_widget_links(self, state):
        for w in self.widgets.itervalues():
            w.set_link_state(state)
        
    def on_widget_interface_update(self, **kwargs):
        widget = kwargs.get('widget')
        address = kwargs.get('address')
        value = kwargs.get('value')
        if widget is not None:
            value = [widget.id] + value
        self.osc_node.get_root_node().send_message(root_address='control', address=['', address], value=value)
        
    def on_widget_add_child(self, **kwargs):
        widget = kwargs.get('widget')
        self._send_widget_to_client(widget=widget)
        
    def on_widget_remove_child(self, **kwargs):
        pass
        
    def on_osc_new_master(self, **kwargs):
        ## link if master is local, unlink if not
        print kwargs
        print self.clients
        if kwargs.get('master_is_local'):
            for c in self.clients.itervalues():
                print 'sending to ', c.name
                self.send_client_interface(name=c.name)
        self.set_widget_links(self.osc_node.oscMaster)
    
    def on_osc_client_added(self, **kwargs):
        client = kwargs.get('client')
        #if 'Control' in client.name:
        if client.port == 8080:
            self.add_client(**kwargs)
            client.sendAllUpdates = True
            
    def on_osc_client_removed(self, **kwargs):
        client = kwargs.get('client')
        #if 'Control' in client.name:
        if client.port == 8080:
            self.remove_client(**kwargs)
            

class PageMenu(OSCBaseObject):
    button_size = dict(w=.2, h=.05)
    def __init__(self, **kwargs):
        self.iOsc = kwargs.get('iOsc')
        self.current_page = None
        kwargs.setdefault('osc_parent_node', self.iOsc.osc_node)
        kwargs.setdefault('osc_address', 'PageMenu')
        super(PageMenu, self).__init__(**kwargs)
        self.x_offset = kwargs.get('x_offset', 0.)
        self.y_offset = kwargs.get('y_offset', 0.)
        #w = self.button_size['w'] * len(PAGES)
        h = self.button_size['h']
        bounds = [self.x_offset, self.y_offset, 1, h]
        self.topwidget = self.iOsc.add_widget('Label', name='PageMenu', bounds=bounds)
        self.btn_topwidget = self.topwidget.add_widget(widgets.Label, name='select_buttons', bounds=bounds)
        self.menu_buttons = ChildGroup(name='select_buttons', osc_parent_node=self.osc_node)
        for i, cls in enumerate(PAGES):
            btn = self.btn_topwidget.add_widget(MenuButton, Index=i, page_cls=cls, parent=self)
            self.menu_buttons.add_child(existing_object=btn)
            btn.connect('state_changed', self.on_menu_button_state_changed)
            
    def set_current_page(self, cls):
        if self.current_page is not None:
            self.current_page.remove()
            self.current_page = None
        if cls is not None:
            self.current_page = cls(iOsc=self.iOsc, y_offset=self.y_offset + self.button_size['h'] + .01)
            
    def on_menu_button_state_changed(self, **kwargs):
        btn = kwargs.get('widget')
        state = kwargs.get('state')
        if state:
            self.set_current_page(btn.cls)
            for w in self.menu_buttons.itervalues():
                if w != btn:
                    w.touch_state = False
            
class MenuButton(widgets.Button):
    def __init__(self, **kwargs):
        self.parent = kwargs.get('parent')
        self.cls = kwargs.get('page_cls')
        i = kwargs.get('Index')
        w = self.parent.button_size['w']
        h = self.parent.button_size['h']
        x = (i * w) + self.parent.x_offset
        y = self.parent.y_offset
        kwargs.setdefault('bounds', [x, y, w, h])
        kwargs.setdefault('label', self.cls.page_name)
        kwargs.setdefault('name', self.cls.page_name)
        super(MenuButton, self).__init__(**kwargs)
        

class MsgLengthError(Exception):
    def __str__(self):
        return 'message length exceeded'
        
